added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / samples / compilers / myc / src / parse.cs
blobe7cd50eaf746e4294fbab2d4c5748547e53b30c5
1 //------------------------------------------------------------------------------
2 // <copyright file="parse.cs" company="Microsoft">
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 // </copyright>
14 //------------------------------------------------------------------------------
16 namespace MyC
18 using System;
19 using System.Text;
21 class Parse
23 private Io io;
24 private Tok tok;
25 private Emit emit;
26 VarList paramvar;
27 VarList localvar;
28 VarList staticvar;
29 int label_count;
30 private bool mainseen = false;
32 void dataClass(Var e)
34 #if DEBUG
35 Console.WriteLine("dataClass1 token=["+tok+"]\n");
36 #endif
37 int id = tok.getId();
38 if (id == Tok.T_EXTERN || id == Tok.T_STATIC || id == Tok.T_AUTO)
40 e.setClassId(tok.getId());
41 tok.scan();
42 #if DEBUG
43 Console.WriteLine("dataClass2 token=["+tok+"]\n");
44 #endif
46 else
48 e.setClassId(Tok.T_DEFCLASS); /* default to current context */
52 void dataType(Var e)
54 int id = tok.getId();
55 #if DEBUG
56 Console.WriteLine("dataType1 token=["+tok+"]\n");
57 #endif
58 e.setSign(Tok.T_SIGNED);
59 if (id == Tok.T_SIGNED || id == Tok.T_UNSIGNED)
61 e.setSign(id);
62 tok.scan();
63 id = tok.getId();
64 #if DEBUG
65 Console.WriteLine("dataType2 token=["+tok+"]\n");
66 #endif
68 if (id == Tok.T_VOID || id == Tok.T_INT)
70 e.setTypeId(id);
71 tok.scan();
72 #if DEBUG
73 Console.WriteLine("dataType3 token=["+tok+"]\n");
74 #endif
76 else if (id == Tok.T_LONG)
77 Io.ICE("Unhandled type LONG");
78 else if (id == Tok.T_CHAR)
79 Io.ICE("Unhandled type CHAR");
80 else if (id == Tok.T_FLOAT)
81 Io.ICE("Unhandled type FLOAT");
82 else if (id == Tok.T_DOUBLE)
83 Io.ICE("Unhandled type DOUBLE");
84 else
85 e.setTypeId(Tok.T_DEFTYPE);
88 VarList paramList()
90 VarList v;
91 tok.scan();
92 if (tok.getFirstChar() != '(')
93 io.Abort("Expected '('");
95 v = new VarList(); /* init the param list */
96 tok.scan(); /* get the next token */
97 while (tok.getFirstChar() != ')')
99 Var e = new Var();
100 e.setClassId(Tok.T_PARAM); /* mark this as a parameter */
101 dataType(e); /* get the specified datatype */
102 e.setName(tok.getValue()); /* copy the variable name */
103 v.add(e); /* add parameter to param list */
104 tok.scan();
105 if (tok.getFirstChar() == ',') /* if more params */
106 tok.scan(); /* get the next token */
108 tok.scan(); /* move to the next token */
109 return v;
112 void outerDecl()
114 Var e = new Var();
115 #if DEBUG
116 Console.WriteLine("outerDecl token=["+tok+"]\n");
117 #endif
119 CommentHolder(); /* mark the position in insn stream */
121 dataClass(e);
122 dataType(e);
124 if (io.getNextChar() == '(')
125 declFunc(e);
126 else
127 declOuter(e);
130 void prolog()
132 emit = new Emit(io);
133 emit.BeginModule(); // need assembly module
134 emit.BeginClass();
137 void epilog()
139 emit.EndClass();
140 emit.EndModule();
143 void addInner(Var e)
146 * validate this declaration as a potential variable
148 int id = e.getClassId();
149 #if DEBUG
150 Console.WriteLine("addInner e=["+e+"]\n");
151 #endif
152 if (id == Tok.T_EXTERN || id == Tok.T_STATIC)
153 io.Abort("Cannot allocate static within a method\n");
154 if (paramvar.FindByName(e.getName()) != null) /* cannot redefine param name */
155 io.Abort("Cannot redefine parameter name '" + e.getName() + "'\n");
156 if (localvar.FindByName(e.getName()) != null) /* check not already set */
157 io.Abort("Local variable '" + e.getName() + "' already defined\n");
158 localvar.add(e);
162 * parse an inner declaration
164 void declInner()
166 while (tok.IsDeclKeyword())
168 Var e = new Var();
169 #if DEBUG
170 Console.WriteLine("declInner1 token=["+tok+"]\n");
171 #endif
173 CommentHolder(); /* mark comment position in insn stream */
175 dataClass(e); // parse the data class (static, auto, etc)
176 dataType(e); // parse the type (int, unsigned, etc)
177 e.setName(tok.getValue()); // save the name in var
178 #if DEBUG
179 Console.WriteLine("declInner2.0 token=["+tok+"]\n");
180 Console.WriteLine("declInner2.0 e=["+e+"]\n");
181 #endif
182 addInner(e); /* add this variable */
184 * loop while there are additional variable names
186 while (io.getNextChar() == ',')
188 tok.scan();
189 if (tok.getFirstChar() != ',')
190 io.Abort("Expected ','");
191 tok.scan();
192 if (tok.getId() != Tok.T_IDENT)
193 io.Abort("Expected identifier");
194 e.setName(tok.getValue()); /* use value as the variable name */
195 #if DEBUG
196 Console.WriteLine("declInner2.1 token=["+tok+"]\n");
197 Console.WriteLine("declInner2.1 e=["+e+"]\n");
198 #endif
199 addInner(e); /* reuse the class & type */
202 * move beyond end of statement indicator
204 tok.scan();
205 if (tok.getFirstChar() != ';')
206 io.Abort("Expected ';'");
207 CommentFill();
208 tok.scan(); /* get token ready nor next parser step */
209 #if DEBUG
210 Console.WriteLine("declInner3 token=["+tok+"]\n");
211 #endif
215 void addOuter(Var e)
217 #if DEBUG
218 Console.WriteLine("addOuter e=["+e+"]\n");
219 #endif
221 * validate this declaration as a potential variable
223 if (e.getClassId() == Tok.T_AUTO)
224 io.Abort("?Cannot allocate automatic variable outside a function\n");
225 if (staticvar.FindByName(e.getName()) != null)
226 io.Abort("?Cannot redefine static name '" + e.getName() + "'\n");
227 staticvar.add(e);
231 * declOuter presumes that class & type have already been parsed
232 * this is done to distinguish between a function declaration and a
233 * variable declaration
235 void declOuter(Var e)
237 #if DEBUG
238 Console.WriteLine("declOuter1 token=["+tok+"]\n");
239 #endif
240 e.setName(tok.getValue()); /* use value as the variable name */
241 addOuter(e); /* add this variable */
242 emit.FieldDef(e); /* issue the declaration */
243 if (e.getClassId() == Tok.T_DEFCLASS)
244 e.setClassId(Tok.T_STATIC); /* make sure it knows its storage class */
247 * loop while there are additional variable names
249 while (io.getNextChar() == ',')
251 tok.scan();
252 if (tok.getFirstChar() != ',')
253 io.Abort("Expected ','");
254 tok.scan();
255 if (tok.getId() != Tok.T_IDENT)
256 io.Abort("Expected identifier");
257 e.setName(tok.getValue()); /* use value as the variable name */
258 addOuter(e); /* add this variable */
259 emit.FieldDef(e); /* issue the declaration */
260 if (e.getClassId() == Tok.T_DEFCLASS)
261 e.setClassId(Tok.T_STATIC); /* make sure it knows its storage class */
264 * move beyond end of statement indicator
266 tok.scan();
267 if (tok.getFirstChar() != ';')
268 io.Abort("Expected ';'");
269 CommentFill();
270 tok.scan();
271 #if DEBUG
272 Console.WriteLine("declOuter2 token=["+tok+"]\n");
273 #endif
276 void declFunc(Var e)
278 #if DEBUG
279 Console.WriteLine("declFunc token=["+tok+"]\n");
280 #endif
281 CommentHolder(); // start new comment
282 e.setName(tok.getValue()); /* value is the function name */
283 if (e.getName().Equals("main"))
285 if (Io.gendll)
286 io.Abort("Using main entrypoint when generating a DLL");
287 mainseen = true;
289 staticvar.add(e); /* add function name to static VarList */
290 paramvar = paramList(); // track current param list
291 e.setParams(paramvar); // and set it in func var
292 localvar = new VarList(); // track new local parameters
293 CommentFillPreTok();
295 emit.FuncBegin(e);
296 if (tok.getFirstChar() != '{')
297 io.Abort("Expected '{'");
298 blockOuter(null, null);
299 emit.FuncEnd();
300 emit.IL();
301 if (Io.genlist)
302 emit.LIST();
303 emit.Finish();
307 * parse the outerBlock seperately from inner block.
308 * specifically parse the declarations at the beginning of an outerblock
309 * the variable r tracks if the last statement was a return or not
311 void blockOuter(String olabel, String ilabel)
313 bool r = false;
314 #if DEBUG
315 Console.WriteLine("blockOuter1 token=["+tok+"]\n");
316 #endif
317 CommentToken(); /* mark the position in insn stream */
318 tok.scan();
319 #if DEBUG
320 Console.WriteLine("blockOuter2 token=["+tok+"]\n");
321 #endif
322 declInner();
323 emit.LocalVars(localvar);
325 while (tok.getFirstChar() != '}')
327 #if DEBUG
328 Console.WriteLine("blockOuter3 token=["+tok+"]\n");
329 #endif
330 if (io.EOF())
331 io.Abort("Expected statement, end of file encountered");
332 r = false;
333 switch (tok.getId())
335 case Tok.T_IF: fcIf(olabel, ilabel); continue; /* fcIf updates tok */
336 case Tok.T_WHILE: fcWhile(); break;
337 case Tok.T_FOR: fcFor(); break;
338 case Tok.T_BREAK: fcBreak(olabel); break;
339 case Tok.T_CONTINUE: fcContinue(ilabel); break;
340 case Tok.T_RETURN: fcReturn(); r = true; break;
341 default: statement(); break;
343 #if DEBUG
344 Console.WriteLine("blockOuter4 token=["+tok+"]\n");
345 #endif
347 if (!r) /* if no outerscope return specified, try to default */
349 Var e = emit.GetFunc(); /* get function def */
350 if (e.getTypeId() != Tok.T_VOID) /* make sure we can default to void */
352 if (!e.getName().Equals("main")) /* is it not main? */
353 io.Abort("No return value specified for non void function");
354 emit.LoadConst("0"); /* special case a dummy ret value */
356 emit.Ret();
358 CommentToken(); /* mark the position in insn stream */
359 tok.scan(); /* read beyond end of block */
360 #if DEBUG
361 Console.WriteLine("blockOuter5 token=["+tok+"]\n");
362 #endif
365 /* recognize and translate a statement block */
366 void blockInner(String olabel, String ilabel)
368 #if DEBUG
369 Console.WriteLine("blockInner1 token=["+tok+"]\n");
370 #endif
371 if (tok.getFirstChar() == '{') /* if begin, then get next token */
373 CommentToken(); /* mark the position in insn stream */
374 tok.scan();
375 #if DEBUG
376 Console.WriteLine("blockInner2 token=["+tok+"]\n");
377 #endif
378 if (tok.IsDeclKeyword())
379 io.Abort("Illegal inner declaration of variable");
380 while (tok.getFirstChar() != '}')
382 switch (tok.getId())
384 case Tok.T_IF: fcIf(olabel, ilabel); continue; /* fcIf updates tvp */
385 case Tok.T_WHILE: fcWhile(); break;
386 case Tok.T_FOR: fcFor(); break;
387 case Tok.T_BREAK: fcBreak(olabel); break;
388 case Tok.T_CONTINUE: fcContinue(ilabel); break;
389 case Tok.T_RETURN: fcReturn(); break;
390 default: statement(); break;
392 #if DEBUG
393 Console.WriteLine("blockInner3 token=["+tok+"]\n");
394 #endif
396 CommentToken(); /* mark the begin of source comment */
397 tok.scan(); /* read beyond end of blockInner */
399 else
401 switch (tok.getId())
403 case Tok.T_IF: fcIf(olabel, ilabel); break;
404 case Tok.T_WHILE: fcWhile(); break;
405 case Tok.T_FOR: fcFor(); break;
406 case Tok.T_BREAK: fcBreak(olabel); break;
407 case Tok.T_CONTINUE: fcContinue(ilabel); break;
408 case Tok.T_RETURN: fcReturn(); break;
409 default: statement(); break;
415 * the flow of control routines
418 /* gen a unique label */
419 String newLabel()
421 StringBuilder sb = new StringBuilder("L");
422 sb.Append(label_count++);
423 return (sb.ToString());
427 * parse an if construct
428 * form is:
429 * if (e) stmt-block else stmt-block
431 void fcIf(String olabel, String ilabel)
433 String label1;
434 String label2;
436 CommentHolder(); /* mark the position in insn stream */
437 tok.scan();
438 if (tok.getFirstChar() != '(')
439 io.Abort("Expected '('");
441 boolExpr();
442 CommentFillPreTok();
444 label1 = newLabel();
445 label2 = String.Copy(label1);
447 emit.Branch("brfalse", label1);
449 blockInner(olabel, ilabel); /* parse block or single statement */
451 #if DEBUG
452 Console.WriteLine("fcIf token=["+tok+"]\n");
453 #endif
454 if (tok.getId() == Tok.T_ELSE) /* sniff for else clause */
456 label2 = newLabel();
457 emit.Branch("br", label2);
459 emit.Label(label1);
460 tok.scan(); /* get next token after else */
461 blockInner(olabel, ilabel); /* outer label, top of loop */
463 emit.Label(label2);
466 /* parse and translate a while statement */
467 void fcWhile()
469 String label1 = newLabel();
470 String label2 = newLabel();
472 CommentHolder(); /* mark the position in insn stream */
473 emit.Label(label1);
474 tok.scan();
475 if (tok.getFirstChar() != '(')
476 io.Abort("Expected '('");
478 boolExpr();
479 CommentFillPreTok();
480 emit.Branch("brfalse", label2);
482 blockInner(label2, label1); /* outer label, top of loop */
483 emit.Branch("br", label1);
485 emit.Label(label2);
488 void fcFor()
490 String label1 = newLabel();
491 String label2 = newLabel();
492 String label3 = newLabel();
493 String label4 = newLabel();
495 CommentHolder(); /* mark the position in insn stream */
496 tok.scan();
497 if (tok.getFirstChar() != '(')
498 io.Abort("Expected '('");
501 * the assignment statement
503 tok.scan(); /* i=0 */
504 if (tok.getFirstChar() == ';') /* allow null assignment */
506 CommentFill();
507 tok.scan(); /* move beyond null statement */
509 else
511 statement(); /* parse the statement */
512 /* statement also closes the comment */
516 * the logical test
518 emit.Label(label1);
519 CommentHolder(); /* mark the position in insn stream */
521 if (tok.getFirstChar() == ';') /* allow null test */
523 CommentFill("<no test>");
524 tok.scan(); /* move past the semi */
526 else
528 boolExpr(); /* i<max */
529 if (tok.getFirstChar() != ';')
530 io.Abort("Expected ';'");
531 CommentFill();
532 tok.scan();
533 emit.Branch("brfalse", label4); /* test for result */
535 emit.Branch("br", label3); /* emit. branch to statement block */
538 * the increment statement
540 CommentHolder(); /* mark comment position in insn stream */
542 emit.Label(label2);
543 if (tok.getFirstChar() == ')') /* allow null increment statement */
545 CommentFill(); /* end comment here */
546 tok.scan(); /* move to next token */
548 else
551 * this is similar to assign, but ends with ')'
553 String varname = tok.getValue();
554 tok.scan();
555 if (tok.getFirstChar() != '=')
556 io.Abort("Expected '='");
557 tok.scan();
558 boolExpr();
559 emit.Store(lookup_name(varname));
560 if (tok.getFirstChar() != ')')
561 io.Abort("Expected ')'");
562 CommentFill(); /* end comment here */
563 tok.scan(); /* move to next token */
565 emit.Branch("br", label1);
568 * the statement block
570 emit.Label(label3);
571 blockInner(label4, label2); /* outer label, top of loop */
572 emit.Branch("br", label2); /* go to 3rd term (usually incr) */
574 emit.Label(label4);
577 /* recognize and translate a break */
578 void fcBreak(String olabel)
580 CommentHolder(); /* mark the position in insn stream */
581 if (olabel != null)
582 emit.Branch("br", olabel);
583 else
584 io.Abort("No loop to break from");
585 tok.scan();
586 if (tok.getFirstChar() != ';')
587 io.Abort("Expected ';'");
588 CommentFill();
589 tok.scan();
592 /* parse a continue */
593 void fcContinue(String ilabel)
595 CommentHolder(); /* mark the position in insn stream */
596 if (ilabel != null)
597 emit.Branch("br", ilabel);
598 else
599 io.Abort("No loop to break from");
600 tok.scan();
601 if (tok.getFirstChar() != ';')
602 io.Abort("Expected ';'");
603 CommentFill();
604 tok.scan();
607 /* parse a return */
608 void fcReturn()
610 Var e = emit.GetFunc();
611 CommentHolder(); /* mark the position in insn stream */
612 tok.scan(); /* get the return value */
613 if (tok.getFirstChar() == ';') /* if end of statment */
615 if (e.getTypeId() != Tok.T_VOID)
616 io.Abort("Expected value for return type");
618 else
620 if (e.getTypeId() == Tok.T_VOID)
621 io.Abort("Unexpected value for void return type");
622 boolExpr(); /* parse as expression */
624 emit.Ret(); /* issue the return (value is on stack) */
625 CommentFill();
626 tok.scan(); /* move past the semi */
630 * expression logic
633 void ident()
635 #if DEBUG
636 Console.WriteLine("ident token=["+tok+"]\n");
637 #endif
638 if (io.getNextChar() == '(') /* this must be a function call */
640 String vname = tok.getValue();
641 Var e;
642 tok.scan(); /* eat the left paren */
643 tok.scan(); /* get the first parameter (or none) */
644 if (tok.getFirstChar() != ')') /* if there are params */
646 boolExpr(); /* parse first param */
647 while (tok.getFirstChar() == ',') /* while there are more params */
649 tok.scan(); /* get the next token */
650 boolExpr(); /* parse now as an expression */
652 if (tok.getFirstChar() != ')') /* must find closing paren */
653 io.Abort("Expected ')'");
654 tok.scan(); /* move to next token */
656 e = staticvar.FindByName(vname); /* find the symbol */
657 if (e.getTypeId() == Tok.T_VOID) /* if function value is void */
658 io.Abort("Using void function where expecting a value");
659 emit.Call(e); /* construct the call */
661 else
663 emit.Load(lookup_name(tok.getValue())); /* load this symbol */
664 tok.scan(); /* get the next token */
668 void factor()
670 #if DEBUG
671 Console.WriteLine("factor token=["+tok+"]\n");
672 #endif
673 if (tok.getFirstChar() == '(')
675 tok.scan(); /* get next token */
676 boolExpr();
677 if (tok.getFirstChar() != ')')
678 io.Abort("Expected ')'");
679 tok.scan(); /* get next token */
681 else if (tok.getId() == Tok.T_IDENT)
683 ident();
685 else
687 emit.LoadConst(tok.getValue());
688 tok.scan(); /* get next token */
692 void unaryFactor()
694 if (tok.getId() == Tok.T_ADD_OP) /* unary plus */
696 tok.scan(); /* get the next token */
697 factor(); /* process the factor */
698 return;
700 if (tok.getId() == Tok.T_SUB_OP) /* unary minus */
702 tok.scan();
703 if (tok.getId() == Tok.T_DIGITS)
705 StringBuilder sb = new StringBuilder("-"); /* recreate the String */
706 sb.Append(tok.getValue());
707 emit.LoadConst(sb.ToString()); /* emit. load const for String */
708 tok.scan();
709 return;
711 factor(); /* process the factor */
712 emit.Insn("neg");
713 return;
715 factor(); /* no unary, so pass this token down */
718 void termMult()
720 tok.scan();
721 factor();
722 emit.Insn("mul");
725 void termDiv()
727 tok.scan();
728 factor();
729 emit.Insn("div");
732 /* completion of term processing (called by term and firstTerm) */
733 void term1()
735 while (tok.getId() == Tok.T_MUL_OP || tok.getId() == Tok.T_DIV_OP)
737 switch (tok.getId())
739 case Tok.T_MUL_OP: termMult(); break;
740 case Tok.T_DIV_OP: termDiv(); break;
745 /* parse and translate math term */
746 void term()
748 factor();
749 term1();
752 /* check term with possible leading sign */
753 void firstTerm()
755 unaryFactor();
756 term1();
759 /* translate an add */
760 void exprAdd()
762 tok.scan();
763 term();
764 emit.Insn("add");
767 /* translate a subtract */
768 void exprSub()
770 tok.scan();
771 term();
772 emit.Insn("sub");
775 /* parse an expression */
776 void mathExpr()
778 #if DEBUG
779 Console.WriteLine("mathExpr1 token=["+tok+"]\n");
780 #endif
781 firstTerm();
782 #if DEBUG
783 Console.WriteLine("mathExpr2 token=["+tok+"]\n");
784 #endif
785 while (tok.getId() == Tok.T_ADD_OP || tok.getId() == Tok.T_SUB_OP)
787 switch (tok.getId())
789 case Tok.T_ADD_OP: exprAdd(); break;
790 case Tok.T_SUB_OP: exprSub(); break;
795 /* recognize and translate a relational "equal" */
796 void relEQ()
798 tok.scan();
799 mathExpr();
800 emit.Insn("ceq");
803 /* recognize and translate a relational "not equal" */
804 void relNEQ()
806 tok.scan();
807 mathExpr();
808 emit.Insn("ceq");
809 emit.LoadConst("1");
810 emit.Insn("ceq");
813 /* recognize and translate a relational "less than" */
814 void relLTR()
816 tok.scan();
817 mathExpr();
818 emit.Insn("clt");
821 /* recognize and translate a relational "greater than" */
822 void relGTR()
824 tok.scan();
825 mathExpr();
826 emit.Insn("cgt");
829 void relGEQ()
831 tok.scan();
832 mathExpr();
833 emit.Insn("clt");
834 emit.LoadConst("0");
835 emit.Insn("ceq");
838 void relLEQ()
840 tok.scan();
841 mathExpr();
842 emit.Insn("cgt");
843 emit.LoadConst("0");
844 emit.Insn("ceq");
847 /* parse a relation */
848 void relExpr()
850 mathExpr();
851 #if DEBUG
852 Console.WriteLine("relExpr token=["+tok+"]\n");
853 #endif
854 switch (tok.getId())
856 case Tok.T_EQ_OP: relEQ(); break;
857 case Tok.T_NEQ_OP: relNEQ(); break;
858 case Tok.T_LT_OP: relLTR(); break;
859 case Tok.T_GT_OP: relGTR(); break;
860 case Tok.T_GE_OP: relGEQ(); break;
861 case Tok.T_LE_OP: relLEQ(); break;
865 /* parse factor with NOT */
866 void notFactor()
868 #if DEBUG
869 Console.WriteLine("notFactor token=["+tok+"]\n");
870 #endif
871 if (tok.getId() == Tok.T_NOT_OP)
873 relExpr();
874 emit.Insn("not");
876 else
877 relExpr();
880 /* recognize and translate a boolean OR */
881 void boolOr()
883 tok.scan();
884 termBool();
885 emit.Insn("or");
888 /* recognize and transate an exclusize or (XOR) */
889 void boolXor()
891 tok.scan();
892 termBool();
893 emit.Insn("xor");
896 /* recognize and transate a bitwise AND */
897 void boolAnd()
899 tok.scan();
900 termBool();
901 emit.Insn("and");
904 /* parse an translate a boolean term */
905 void termBool()
907 notFactor();
908 while (tok.getId() == Tok.T_OR_OP
909 || tok.getId() == Tok.T_XOR_OP
910 || tok.getId() == Tok.T_AND_OP)
912 switch (tok.getId())
914 case Tok.T_OR_OP: boolOr(); break;
915 case Tok.T_XOR_OP: boolXor(); break;
916 case Tok.T_AND_OP: boolAnd(); break;
918 #if DEBUG
919 Console.WriteLine("termBool token=["+tok+"]\n");
920 #endif
924 /* parse and translate a boolean expression */
925 void boolExpr()
927 termBool();
928 int id = tok.getId();
929 if (id == Tok.T_LOG_OR_OP || id == Tok.T_LOG_AND_OP)
931 String label1 = newLabel();
932 String label2 = newLabel();
933 String label3 = newLabel();
934 while (true)
936 id = tok.getId();
937 if (id == Tok.T_LOG_AND_OP)
938 emit.Branch("brfalse", label1); // optimize the logical and
939 else if (id == Tok.T_LOG_OR_OP)
940 emit.Branch("brtrue", label2); // optimize the logical or
941 else
942 break;
943 tok.scan();
944 termBool();
946 emit.Branch("brtrue", label2);
947 emit.Label(label1); // false path
948 emit.LoadConst("0");
949 emit.Branch("br",label3);
950 emit.Label(label2); // true path
951 emit.LoadConst("1");
952 emit.Label(label3); // common path
956 Var lookup_name(String s)
958 Var e;
959 if ((e = localvar.FindByName(s)) == null)
960 if ((e = paramvar.FindByName(s)) == null)
961 if ((e = staticvar.FindByName(s)) == null)
963 io.Abort("Undefined variable '"+ s + "'\n");
965 return e;
969 * parse a generic statement
971 * possible forms are:
972 * lvalue = <expr> ;
973 * function() ;
974 * and <expr> can contain: function or arithmetic expressions
976 * so for a recursive descent parser we need to test for a possible
977 * '=' or '('
979 void statement()
981 Var e;
982 String vname = tok.getValue();
984 CommentHolder(); /* mark the position in insn stream */
985 switch (io.getNextChar())
987 case '(': /* this is a function call */
988 tok.scan();
989 if (tok.getFirstChar() != '(')
990 io.Abort("Expected '('");
991 tok.scan(); /* get the first parameter (or none) */
992 if (tok.getFirstChar() != ')') /* if there are params */
994 boolExpr(); /* parse first param */
995 while (tok.getFirstChar() == ',') /* while there are more params */
997 tok.scan(); /* get the next token */
998 boolExpr(); /* parse now as an expression */
1000 if (tok.getFirstChar() != ')') /* must find closing paren */
1001 io.Abort("Expected ')'");
1003 CommentFill();
1004 tok.scan(); /* move to next token */
1005 e = staticvar.FindByName(vname); /* find the symbol (e cannot be null) */
1006 emit.Call(e);
1007 if (e.getTypeId() != Tok.T_VOID) /* if function value not void */
1008 emit.Insn("pop"); /* then pop the unused return value */
1009 break;
1010 case '=': /* if we have equal, then parse assign */
1011 tok.scan();
1012 if (tok.getFirstChar() != '=')
1013 io.Abort("Expected '='");
1014 tok.scan();
1015 boolExpr();
1016 CommentFill();
1017 emit.Store(lookup_name(vname));
1018 break;
1019 default:
1021 StringBuilder sb = new StringBuilder();
1022 sb.Append("Unexpected character '");
1023 sb.Append(io.getNextChar());
1024 sb.Append("'\n");
1025 io.Abort(sb.ToString());
1026 return;
1029 if (tok.getFirstChar() != ';')
1030 io.Abort("Expected ';'");
1031 tok.scan();
1034 public Parse(Io i, Tok t)
1036 io = i;
1037 tok = t;
1038 staticvar = new VarList(); // init the static variables list
1041 /* parse and translate a program */
1042 public void program()
1044 prolog();
1045 while (tok.NotEOF())
1047 outerDecl();
1049 if (Io.genexe && !mainseen)
1050 io.Abort("Generating executable with no main entrypoint");
1051 epilog();
1054 void CommentToken()
1056 io.commentBegin(tok.getValue()); /* mark the begin of source comment */
1057 emit.CommentHolder();
1058 emit.CommentFill(io.commentEndTok(tok.getValue())); /* copy and emit comment */
1061 void CommentHolder()
1063 io.commentBegin(tok.getValue()); /* mark the begin of source comment */
1064 emit.CommentHolder();
1067 void CommentFill()
1069 emit.CommentFill(io.commentEndTok(tok.getValue())); /* copy and emit comment */
1072 void CommentFill(String s)
1074 emit.CommentFill(io.commentEndTok(tok.getValue()) + s); /* end the comment (no test) */
1077 void CommentFillPreTok()
1079 emit.CommentFill(io.commentEndPreTok(tok.getValue())); /* copy and emit source */